// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: agent for vbs
// feature: destination order support by reception timestamp
// feature: support batch send
// feature: E2E protection
// feature: flowcontroller xml config and writer/reader-resourcelimit
// ------------------------------------------------------------------

#ifndef XMLPARSER_QOS_DATAREADERQOS_HPP_
#define XMLPARSER_QOS_DATAREADERQOS_HPP_

#include <xmlparser/attributes/XMLReaderAttributes.h>
#include <xmlparser/attributes/XMLTopicAttributes.h>

#include <xmlparser/qos/XMLQosPolicies.hpp>
#include <xmlparser/qos/XMLReaderQos.hpp>
#include <xmlparser/qos/XMLSubscriberQos.hpp>

namespace vbsutil {
namespace xmlparser {

using TopicAttributesQos = vbsutil::xmlparser::TopicAttributes;

//! Qos Policy to configure the DisablePositiveACKsQos and the reader attributes
class RTPSReliableReaderQos {
 public:
    /**
     * @brief Constructor
     */
    RTPS_DllAPI RTPSReliableReaderQos() {}

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~RTPSReliableReaderQos() = default;

    bool operator==(const RTPSReliableReaderQos& b) const {
        return (this->times == b.times) && (this->disable_positive_ACKs == b.disable_positive_ACKs);
    }

    inline void clear() {
        RTPSReliableReaderQos reset = RTPSReliableReaderQos();
        std::swap(*this, reset);
    }

    /*!
     * @brief Times associated with the Reliable Readers events.
     */
    ReaderTimes times;

    /*!
     * @brief Control the sending of positive ACKs
     */
    DisablePositiveACKsQosPolicy disable_positive_ACKs;
};

//! Qos Policy to configure the limit of the reader resources
class ReaderResourceLimitsQos {
 public:
    /**
     * @brief Constructor
     */
    RTPS_DllAPI ReaderResourceLimitsQos() = default;

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~ReaderResourceLimitsQos() = default;

    bool operator==(const ReaderResourceLimitsQos& b) const {
        return (matched_publisher_allocation == b.matched_publisher_allocation) &&
               (sample_infos_allocation == b.sample_infos_allocation) &&
               (outstanding_reads_allocation == b.outstanding_reads_allocation) &&
               (max_samples_per_read == b.max_samples_per_read);
    }

    inline void clear() {
        ReaderResourceLimitsQos reset = ReaderResourceLimitsQos();
        std::swap(*this, reset);
    }

    //! Matched publishers allocation limits.
    ResourceLimitedContainerConfig matched_publisher_allocation;
    //! SampleInfo allocation limits.
    ResourceLimitedContainerConfig sample_infos_allocation {32u};
    //! Loaned collections allocation limits.
    ResourceLimitedContainerConfig outstanding_reads_allocation {2u};

    /**
     * Maximum number of samples to return on a single call to read / take.
     *
     * This attribute is a signed integer to be consistent with the @c max_samples argument of
     * @ref DataReader methods, but should always have a strict positive value. Bear in mind that
     * a big number here may cause the creation of the DataReader to fail due to pre-allocation of
     * internal resources.
     *
     * Default value: 100.
     */
    int32_t max_samples_per_read = 100;
};

/**
 * Class DataReaderQos, containing all the possible Qos that can be set for a determined DataReader.
 * Although these values can be set and are transmitted
 * during the Endpoint Discovery Protocol, not all of the behaviour associated with them has been
 * implemented in the library. Please consult each of them to check for implementation details and
 * default values.
 * @ingroup EDDS_QOS_MODULE
 */
class DataReaderQos : public BaseDataReaderQos {
 public:
    /**
     * @brief Constructor
     */
    RTPS_DllAPI DataReaderQos() {}

    RTPS_DllAPI bool operator==(const DataReaderQos& b) const {
        return (durability_ == b.durability()) && (deadline_ == b.deadline()) && (liveliness_ == b.liveliness()) &&
               (reliability_ == b.reliability()) && (history_ == b.history()) &&
               (resource_limits_ == b.resource_limits()) && (ownership_ == b.ownership()) &&
               (lifespan_ == b.lifespan()) && (reliable_reader_qos_ == b.reliable_reader_qos()) &&
               (properties_ == b.properties()) && (endpoint_ == b.endpoint()) &&
               (reader_resource_limits_ == b.reader_resource_limits()) && (e2e_protection_ == b.e2e_protection()) &&
               (destination_order_ == b.destination_order()) && (ipc_mode_ == b.ipc_mode()) &&
               (agent_flag_ == b.agent_flag());
    }

    void exportDataReaderQosInfo() const;

    RTPS_DllAPI ReaderQos get_readerqos(const SubscriberQos& sqos) const;

    /**
     * Getter for DeadlineQosPolicy
     *
     * @return DeadlineQosPolicy reference
     */
    RTPS_DllAPI DeadlineQosPolicy& deadline() { return deadline_; }

    /**
     * Getter for DeadlineQosPolicy
     *
     * @return DeadlineQosPolicy const reference
     */
    RTPS_DllAPI const DeadlineQosPolicy& deadline() const { return deadline_; }

    /**
     * Setter for DeadlineQosPolicy
     *
     * @param new_value new value for the DeadlineQosPolicy
     */
    RTPS_DllAPI void deadline(const DeadlineQosPolicy& new_value) { deadline_ = new_value; }

    /**
     * Getter for LivelinessQosPolicy
     *
     * @return LivelinessQosPolicy reference
     */
    RTPS_DllAPI LivelinessQosPolicy& liveliness() { return liveliness_; }

    /**
     * Getter for LivelinessQosPolicy
     *
     * @return LivelinessQosPolicy const reference
     */
    RTPS_DllAPI const LivelinessQosPolicy& liveliness() const { return liveliness_; }

    /**
     * Setter for LivelinessQosPolicy
     *
     * @param new_value new value for the LivelinessQosPolicy
     */
    RTPS_DllAPI void liveliness(const LivelinessQosPolicy& new_value) { liveliness_ = new_value; }

    /**
     * Getter for HistoryQosPolicy
     *
     * @return HistoryQosPolicy reference
     */
    RTPS_DllAPI HistoryQosPolicy& history() { return history_; }

    /**
     * Getter for HistoryQosPolicy
     *
     * @return HistoryQosPolicy const reference
     */
    RTPS_DllAPI const HistoryQosPolicy& history() const { return history_; }

    /**
     * Setter for HistoryQosPolicy
     *
     * @param new_value new value for the HistoryQosPolicy
     */
    RTPS_DllAPI void history(const HistoryQosPolicy& new_value) { history_ = new_value; }

    /**
     * Getter for ResourceLimitsQosPolicy
     *
     * @return ResourceLimitsQosPolicy reference
     */
    RTPS_DllAPI ResourceLimitsQosPolicy& resource_limits() { return resource_limits_; }

    /**
     * Getter for ResourceLimitsQosPolicy
     *
     * @return ResourceLimitsQosPolicy const reference
     */
    RTPS_DllAPI const ResourceLimitsQosPolicy& resource_limits() const { return resource_limits_; }

    /**
     * Setter for ResourceLimitsQosPolicy
     *
     * @param new_value new value for the ResourceLimitsQosPolicy
     */
    RTPS_DllAPI void resource_limits(const ResourceLimitsQosPolicy& new_value) { resource_limits_ = new_value; }

    /**
     * Getter for OwnershipQosPolicy
     *
     * @return OwnershipQosPolicy reference
     */
    RTPS_DllAPI OwnershipQosPolicy& ownership() { return ownership_; }

    /**
     * Getter for OwnershipQosPolicy
     *
     * @return OwnershipQosPolicy const reference
     */
    RTPS_DllAPI const OwnershipQosPolicy& ownership() const { return ownership_; }

    /**
     * Setter for OwnershipQosPolicy
     *
     * @param new_value new value for the OwnershipQosPolicy
     */
    RTPS_DllAPI void ownership(const OwnershipQosPolicy& new_value) { ownership_ = new_value; }

    /**
     * Getter for LifespanQosPolicy
     *
     * @return LifespanQosPolicy reference
     */
    RTPS_DllAPI LifespanQosPolicy& lifespan() { return lifespan_; }

    /**
     * Getter for LifespanQosPolicy
     *
     * @return LifespanQosPolicy const reference
     */
    RTPS_DllAPI const LifespanQosPolicy& lifespan() const { return lifespan_; }

    /**
     * Setter for LifespanQosPolicy
     *
     * @param new_value new value for the LifespanQosPolicy
     */
    RTPS_DllAPI void lifespan(const LifespanQosPolicy& new_value) { lifespan_ = new_value; }

    /**
     * Getter for RTPSReliableReaderQos
     *
     * @return RTPSReliableReaderQos reference
     */
    RTPS_DllAPI RTPSReliableReaderQos& reliable_reader_qos() { return reliable_reader_qos_; }

    /**
     * Getter for RTPSReliableReaderQos
     *
     * @return RTPSReliableReaderQos const reference
     */
    RTPS_DllAPI const RTPSReliableReaderQos& reliable_reader_qos() const { return reliable_reader_qos_; }

    /**
     * Setter for RTPSReliableReaderQos
     *
     * @param new_value new value for the RTPSReliableReaderQos
     */
    RTPS_DllAPI void reliable_reader_qos(const RTPSReliableReaderQos& new_value) { reliable_reader_qos_ = new_value; }

    /**
     * Getter for ReaderResourceLimitsQos
     *
     * @return ReaderResourceLimitsQos reference
     */
    RTPS_DllAPI ReaderResourceLimitsQos& reader_resource_limits() { return reader_resource_limits_; }

    /**
     * Getter for ReaderResourceLimitsQos
     *
     * @return ReaderResourceLimitsQos const reference
     */
    RTPS_DllAPI const ReaderResourceLimitsQos& reader_resource_limits() const { return reader_resource_limits_; }

    /**
     * Setter for ReaderResourceLimitsQos
     *
     * @param new_value new value for the ReaderResourceLimitsQos
     */
    RTPS_DllAPI void reader_resource_limits(const ReaderResourceLimitsQos& new_value) {
        reader_resource_limits_ = new_value;
    }

    /**
     * Getter for E2EProtectionQosPolicy
     *
     * @return E2EProtectionQosPolicy reference
     */
    RTPS_DllAPI E2EProtectionQosPolicy& e2e_protection() { return e2e_protection_; }

    /**
     * Getter for E2EProtectionQosPolicy
     *
     * @return E2EProtectionQosPolicy reference
     */
    RTPS_DllAPI const E2EProtectionQosPolicy& e2e_protection() const { return e2e_protection_; }

    /**
     * Setter for E2EProtectionQosPolicy
     *
     * @param e2e_protection new value for the E2EProtectionQosPolicy
     */
    RTPS_DllAPI void e2e_protection(const E2EProtectionQosPolicy& e2e_protection) { e2e_protection_ = e2e_protection; }

    /**
     * Getter for sendMulti
     *
     * @return sendMulti reference
     */
    const bool& send_multi() const { return send_multi_; }

    /**
     * Setter for sendMulti
     *
     * @param send_multi new value for the sendMulti
     */
    void send_multi(const bool& send_multi) { send_multi_ = send_multi; }

    const uint8_t& ipc_mode() const { return ipc_mode_; }

    void ipc_mode(const uint8_t& ipc_mode) { ipc_mode_ = ipc_mode; }

    const uint8_t& agent_flag() const { return agent_flag_; }

    void agent_flag(const uint8_t& flag) { agent_flag_ = flag; }

    /**
     * Getter for DestinationOrderQosPolicy
     *
     * @return DestinationOrderQosPolicy reference
     */
    RTPS_DllAPI DestinationOrderQosPolicy& destination_order() { return destination_order_; }

    /**
     * Getter for DestinationOrderQosPolicy
     *
     * @return DestinationOrderQosPolicy const reference
     */
    RTPS_DllAPI const DestinationOrderQosPolicy& destination_order() const { return destination_order_; }

    /**
     * Setter for DestinationOrderQosPolicy
     *
     * @param new_value new value for the DestinationOrderQosPolicy
     */
    RTPS_DllAPI void destination_order(const DestinationOrderQosPolicy& new_value) { destination_order_ = new_value; }

 private:
    //! Deadline Qos, implemented in the library.
    DeadlineQosPolicy deadline_;

    //! Liveliness Qos, implemented in the library.
    LivelinessQosPolicy liveliness_;

    //! History Qos, implemented in the library.
    HistoryQosPolicy history_;

    //! Resource Limits Qos, implemented in the library.
    ResourceLimitsQosPolicy resource_limits_;

    //! Ownership Qos, implemented in the library.
    OwnershipQosPolicy ownership_;

    //! Lifespan Qos (Extension).
    LifespanQosPolicy lifespan_;

    //! Reliable reader configuration (Extension)
    RTPSReliableReaderQos reliable_reader_qos_;

    //! ReaderResourceLimitsQos
    ReaderResourceLimitsQos reader_resource_limits_;

    //! E2EProtectionQosPolicy
    E2EProtectionQosPolicy e2e_protection_;

    //!Destination Order Qos
    DestinationOrderQosPolicy destination_order_;

    //! Whether sending multiple copies is supported
    bool send_multi_ = false;

    uint8_t ipc_mode_ = 0;

    uint8_t agent_flag_ = 0;
};

// RTPS_DllAPI extern const DataReaderQos DATAREADER_QOS_DEFAULT;
const DataReaderQos& getDefaultDataReaderQos();

}  // namespace xmlparser
}  // namespace vbsutil

#endif  // INCLUDE_EDDS_DDS_SUBSCRIBER_QOS_DATAREADERQOS_HPP_
